package controllers

import (
	"bankend/config"
	"bankend/database"
	"bankend/models"
	"bankend/services"
	"bytes"
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// WeChatToken 处理 /wx/weChatToken 的 GET 请求，做签名校验并返回 echostr
func WeChatToken(c *gin.Context) {
	signature := c.Query("signature")
	timestamp := c.Query("timestamp")
	nonce := c.Query("nonce")
	echostr := c.Query("echostr")

	if checkSignature(signature, timestamp, nonce) {
		c.String(http.StatusOK, echostr)
		return
	}
	c.String(http.StatusForbidden, "forbidden")
}

// checkSignature 按字典序排序 token、timestamp、nonce，SHA1 加密后与 signature 比对
func checkSignature(signature, timestamp, nonce string) bool {
	arr := []string{config.TOKEN, timestamp, nonce}
	sort.Strings(arr)
	raw := strings.Join(arr, "")

	h := sha1.New()
	h.Write([]byte(raw))
	sum := h.Sum(nil)

	expected := hex.EncodeToString(sum)
	return expected == signature
}

// GetUserCode GET /wx/getUserCode
// 重定向到微信 OAuth2 授权页面
func GetUserCode(c *gin.Context) {
	appid := config.AppConfig.WxAppID
	// 回调 URL 必须在公众号后台配置白名单中
	backURL := url.QueryEscape("http://xt77eg.natappfree.cc/wx/getUserOpenId")
	authURL := fmt.Sprintf(
		"https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect",
		appid, backURL,
	)
	c.Redirect(http.StatusFound, authURL)
}

// GetUserOpenId GET /wx/getUserOpenId
// 接收微信回调的 code，向微信接口换取 openid 并返回
func GetUserOpenId(c *gin.Context) {
	code := c.Query("code")
	if code == "" {
		c.String(http.StatusBadRequest, "missing code")
		return
	}

	appid := config.AppConfig.WxAppID
	secret := config.AppConfig.WxSecret
	tokenURL := fmt.Sprintf(
		"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
		appid, secret, code,
	)

	resp, err := http.Get(tokenURL)
	if err != nil {
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	defer resp.Body.Close()

	var result struct {
		OpenID  string `json:"openid"`
		ErrCode int    `json:"errcode"`
		ErrMsg  string `json:"errmsg"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	if result.ErrCode != 0 {
		c.String(http.StatusBadRequest, fmt.Sprintf("wechat error %d: %s", result.ErrCode, result.ErrMsg))
		return
	}

	c.String(http.StatusOK, result.OpenID)
}

// WeChatEventMessage 统一结构，接收微信服务器推送的 XML
type WeChatEventMessage struct {
	XMLName      xml.Name `xml:"xml"`
	ToUserName   string   `xml:"ToUserName"`
	FromUserName string   `xml:"FromUserName"`
	CreateTime   int64    `xml:"CreateTime"`
	MsgType      string   `xml:"MsgType"`
	Event        string   `xml:"Event"`
	EventKey     string   `xml:"EventKey"`
	Ticket       string   `xml:"Ticket"`
	Latitude     string   `xml:"Latitude"`
	Longitude    string   `xml:"Longitude"`
	Precision    string   `xml:"Precision"`
}

// TextResponse 用于被动回复文本消息
type TextResponse struct {
	XMLName      xml.Name `xml:"xml"`
	ToUserName   CDATA    `xml:"ToUserName"`
	FromUserName CDATA    `xml:"FromUserName"`
	CreateTime   int64    `xml:"CreateTime"`
	MsgType      CDATA    `xml:"MsgType"`
	Content      CDATA    `xml:"Content"`
}

type CDATA struct {
	Text string `xml:",cdata"`
}

// HandleWeChatEvent 接收微信所有事件推送
func HandleWeChatEvent(c *gin.Context) {
	log.Println("[WX Event] 收到事件推送")
	log.Println("请求参数：")
	log.Println(c.Request.URL.Query())
	// 验签：调用公共的 checkSignature
	if !checkSignature(c.Query("signature"), c.Query("timestamp"), c.Query("nonce")) {
		log.Println("[WX Event] 签名校验失败")
		c.String(http.StatusForbidden, "forbidden")
		return
	}

	var evt WeChatEventMessage
	if err := c.ShouldBindXML(&evt); err != nil {
		log.Printf("[WX Event] 解析 XML 失败: %v", err)
		c.String(http.StatusBadRequest, "")
		return
	}
	log.Printf("[WX Event] 收到事件 MsgType=%s, Event=%s, EventKey=%s",
		evt.MsgType, evt.Event, evt.EventKey)

	switch strings.ToLower(evt.MsgType) {
	case "event":
		switch strings.ToLower(evt.Event) {
		case "subscribe":
			onSubscribe(evt.FromUserName)
		case "unsubscribe":
			onUnsubscribe(evt.FromUserName)
		case "click":
			onClick(c, evt.FromUserName, evt.EventKey)
		case "view":
			onView(c, evt.FromUserName, evt.EventKey)
		default:
			log.Printf("[WX Event] 未处理的 event: %s", evt.Event)
		}
	default:
		log.Printf("[WX Event] 非事件类型: %s", evt.MsgType)
	}

	// 必须返回空串
	c.String(http.StatusOK, "")
}

// onSubscribe 标记订阅并推送欢迎模板
func onSubscribe(openid string) {
	log.Printf("[WX Subscribe] %s", openid)
	database.DB.Model(&models.User{}).
		Where("openid = ?", openid).
		Update("subscribed", true)

	if err := services.SendTemplateMessage(services.TemplateMessageData{
		OpenID:     openid,
		TemplateID: "scJNtGT3K4wY4KnqlVaoFjWf8IcyOGeGwCmXlS9fSZk",
		URL:        "",
		Data: map[string]string{
			"first":  "欢迎关注！",
			"remark": "感谢您的关注。",
		},
	}); err != nil {
		log.Printf("[WX Subscribe] 模板推送失败: %v", err)
	}
}

func onUnsubscribe(openid string) {
	log.Printf("[WX Unsubscribe] %s", openid)
	database.DB.Model(&models.User{}).
		Where("openid = ?", openid).
		Update("subscribed", false)
}

func onClick(c *gin.Context, openid, key string) {
	log.Printf("[WX Click] openid=%s, key=%s", openid, key)
	replyText(c, openid, "您点击了菜单："+key)

	switch key {
	case "event_1":
		// 发送模板消息测试
		log.Println("[WX Click] 收到event_1点击，准备发送模板消息")
		if err := services.SendTemplateMessage(services.TemplateMessageData{
			OpenID:     openid,
			TemplateID: "gKuSV5btbvI2dhbdUzErl-0dIW-fLmEWCe3KFteR_3s",
			URL:        "http://weixin.qq.com/download", // 可选：点击跳转链接
			Data: map[string]string{
				"first":    "您有一条新的测试消息",
				"keyword1": "测试内容",
				"keyword2": time.Now().Format("2006-01-02 15:04:05"),
				"keyword3": "系统自动发送",
				"remark":   "感谢您的使用！",
			},
		}); err != nil {
			log.Printf("[WX Click] 模板消息发送失败: %v", err)
		} else {
			log.Println("[WX Click] 模板消息发送成功")
		}
	default:
		// 其他菜单点击事件处理
	}
}

func onView(c *gin.Context, openid, url string) {
	log.Printf("[WX View] openid=%s, url=%s", openid, url)
	replyText(c, openid, "即将打开："+url)
}

// replyText 正确使用 c，将 XML 写回给微信
func replyText(c *gin.Context, toOpenID, content string) {
	resp := TextResponse{
		ToUserName:   CDATA{toOpenID},
		FromUserName: CDATA{config.AppConfig.WxAppID},
		CreateTime:   time.Now().Unix(),
		MsgType:      CDATA{"text"},
		Content:      CDATA{content},
	}
	c.XML(http.StatusOK, resp)
}

// GetAccessToken GET /wx/getAccessToken
// 获取微信 access_token（需要管理员权限）
func GetAccessToken(c *gin.Context) {
	// 从上下文获取用户名（JWT中间件设置）
	username, exists := c.Get("username")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "需要登录"})
		return
	}

	// 检查用户权限
	var user models.User
	if err := database.DB.Where("username = ? AND deleted_at IS NULL", username).First(&user).Error; err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "用户不存在"})
		return
	}
	if user.Role != "管理员" {
		c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
		return
	}

	// 调用service获取token
	token, err := services.GetAccessToken()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("获取access_token失败: %v", err),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"access_token": token,
		"expires_at":   services.GetTokenExpireTime(),
	})
}

// GetMenuConfig GET /wx/menu/get
// 获取微信公众号菜单配置
func GetMenuConfig(c *gin.Context) {
	// 1. 获取access_token
	token, err := services.GetAccessToken()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("获取access_token失败: %v", err),
		})
		return
	}

	// 2. 请求微信API
	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/menu/get?access_token=%s", token)
	resp, err := http.Get(url)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("请求微信接口失败: %v", err),
		})
		return
	}
	defer resp.Body.Close()

	// 3. 读取并转发微信响应
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("读取响应失败: %v", err),
		})
		return
	}

	// 4. 直接返回微信API的原始JSON响应
	c.Header("Content-Type", "application/json")
	c.String(http.StatusOK, string(body))
}

// SaveMenuConfig POST /wx/menu/create
// 保存微信公众号菜单配置
func SaveMenuConfig(c *gin.Context) {
	// 1. 获取access_token
	token, err := services.GetAccessToken()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("获取access_token失败: %v", err),
		})
		return
	}

	// 2. 读取请求体
	body, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("读取请求数据失败: %v", err),
		})
		return
	}

	// 3. 转发请求到微信API
	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s", token)
	resp, err := http.Post(url, "application/json", bytes.NewBuffer(body))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("请求微信接口失败: %v", err),
		})
		return
	}
	defer resp.Body.Close()

	// 4. 读取并转发微信响应
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("读取响应失败: %v", err),
		})
		return
	}

	// 5. 直接返回微信API的原始JSON响应
	c.Header("Content-Type", "application/json")
	c.String(http.StatusOK, string(respBody))
}

// SendMassMessage POST /wx/mass/sendall
// 群发文本消息
func SendMassMessage(c *gin.Context) {
	// 1. 权限检查
	username, exists := c.Get("username")
	if !exists {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "需要登录"})
		return
	}

	var user models.User
	if err := database.DB.Where("username = ? AND deleted_at IS NULL", username).First(&user).Error; err != nil {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "用户不存在"})
		return
	}
	if user.Role != "管理员" {
		c.JSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"})
		return
	}

	// 2. 获取access_token
	token, err := services.GetAccessToken()
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("获取access_token失败: %v", err),
		})
		return
	}

	// 3. 读取请求体
	var reqBody struct {
		Filter struct {
			IsToAll bool  `json:"is_to_all"`
			TagID   int64 `json:"tag_id,omitempty"`
		} `json:"filter"`
		Text struct {
			Content string `json:"content"`
		} `json:"text"`
		MsgType string `json:"msgtype"`
	}

	if err := c.ShouldBindJSON(&reqBody); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": fmt.Sprintf("请求数据格式错误: %v", err),
		})
		return
	}

	// 4. 调用微信群发接口
	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=%s", token)
	
	// Fix: Read the request body first
	jsonData, err := json.Marshal(reqBody)
	if err != nil {
	    c.JSON(http.StatusBadRequest, gin.H{
	        "error": fmt.Sprintf("序列化请求数据失败: %v", err),
	    })
	    return
	}
	
	resp, err := http.Post(url, "application/json", bytes.NewReader(jsonData))
	if err != nil {
	    c.JSON(http.StatusInternalServerError, gin.H{
	        "error": fmt.Sprintf("请求微信接口失败: %v", err),
	    })
	    return
	}
	defer resp.Body.Close()

	// 5. 读取并转发微信响应
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"error": fmt.Sprintf("读取响应失败: %v", err),
		})
		return
	}

	// 6. 记录日志
	log.Printf("[SendMassMessage] Response: %s", string(body))

	// 7. 返回微信原始响应
	c.Header("Content-Type", "application/json")
	c.String(http.StatusOK, string(body))
}
